package com.rock.upms.autocode.util;

import java.io.File;

import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.ObjectUtils;
import org.apache.velocity.VelocityContext;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.rock.common.util.AESUtil;
import com.rock.common.util.FileUtil;
import com.rock.common.util.JdbcUtil;
import com.rock.common.util.StringUtil;
import com.rock.upms.autocode.config.AutoCfg;

/**
 * 代码生成类 Created by zhousq on 2017/1/10.
 */
public class MybatisGeneratUtil {

	private static Logger log = LoggerFactory.getLogger(MybatisGeneratUtil.class);
	// generatorConfig模板路径
	private static String generatorConfigVm = "/template/generatorConfig.vm";
	// Service接口模板路径
	private static String iserviceVm = "/template/iservice.vm";
	// Service实现类模板路径
	private static String serviceImplVm = "/template/service.vm";
	// ServiceMock模板路径
	// private static String serviceMockVm = "/template/serviceMock.vm";
	// 模态方式crud模板
	private static String modalCrudJspVm = "/template/web/modal-crud-jsp.vm";
	private static String modalControllerVm = "/template/web/modal-controller-vm.java";
	private static List<Map<String, String>> tableList = new ArrayList<Map<String, String>>();

	/**
	 * 构造函数，初始化tables，供后续使用
	 */
	public MybatisGeneratUtil() {
		String databaseType = AutoCfg.getDatabaseType();
		String tableSql = "";
		if ("oracle".equals(databaseType)) {
			tableSql = "select table_name from  dba_tables where tablespace_name='" + AutoCfg.getOraclTablespaceName().toUpperCase() + "' and table_name LIKE '"
					+ AutoCfg.getTablePrefix().toUpperCase() + "%'";
		}
		if ("mysql".equals(databaseType)) {
			tableSql = "SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = '" + AutoCfg.getDatabaseName() + "' AND table_name LIKE '"
					+ AutoCfg.getTablePrefix().toUpperCase() + "_%';";
		}
		// 查询定制前缀项目的所有表
		log.trace("======>jdbc password:" + AESUtil.getInstance().decrypt(AutoCfg.getJdbcPassword()));
		log.trace("======>jdbc user:" + AutoCfg.getJdbcUsername());
		JdbcUtil jdbcUtil = new JdbcUtil(AutoCfg.getJdbcDriver(), AutoCfg.getJdbcUrl(), AutoCfg.getJdbcUsername(), AESUtil.getInstance().decrypt(AutoCfg.getJdbcPassword()));
		List<Map> result;
		try {
			result = jdbcUtil.selectByParams(tableSql, null);
			Map<String, String> table;
			for (Map<?, ?> map : result) {
				table = new HashMap<>();
				table.put("table_name", ObjectUtils.toString(map.get("TABLE_NAME")));
				table.put("entity_name", StringUtil.lineToHump(ObjectUtils.toString(map.get("TABLE_NAME"))));
				tableList.add(table);
			}
			log.trace("======>tableList size:" + tableList.size());
		} catch (SQLException e) {
			e.printStackTrace();
		}
		jdbcUtil.release();
	}

	/**
	 * 方法名：generatModel 功能：生成模型实体类、实体查询类、mapper接口、mapper xml映射文件
	 * 
	 * @param return_insert_id_tables
	 *            插入需返回主键的表集合
	 */
	public void generatModelAndMapper(Map<String, String> return_insert_id_tables) throws Exception {
		log.trace("======>generatModel begin");
		VelocityContext myatisContext = new VelocityContext();
		// 模板文件路径
		generatorConfigVm = MybatisGeneratUtil.class.getResource(generatorConfigVm).getPath().replaceFirst("/", "");
		// mybatis配置文件目标路径
		String generatorConfig_xml = MybatisGeneratUtil.class.getResource("/").getPath().replace("/target/classes/", "") + "/src/main/resources/generatorConfig.xml";
		if (tableList != null) {
			myatisContext.put("tables", tableList);
			// 实体类包名com.rock.upms.model
			myatisContext.put("entityPackageName", "com.rock." + AutoCfg.getSystemCode() + ".model");
			// 映射文件包名com.rock.upms.svc.dao.model.mapper.UpmsDepartmentMapper.xml
			myatisContext.put("mapperXMLPackageName", "com.rock." + AutoCfg.getSystemCode() + ".svc.dao.model.mapper");
			// 映射接口类包名(同xml文件包名)com.rock.upms.svc.dao.model.mapper.UpmsDepartmentMapper.java
			myatisContext.put("mapperPackageName", "com.rock." + AutoCfg.getSystemCode() + ".svc.dao.model.mapper");
			// model源代码文件夹路径：代码位置/系统文件夹名（rock-upms）/工程文件夹名（rock-upms-model）/java文件路径（src/main/java）
			String javaModelFoderPath = AutoCfg.getCodePath() + "/rock-" + AutoCfg.getSystemCode() + "/rock-" + AutoCfg.getSystemCode() + "-model/src/main/java";
			String javaMapperFoderPath = AutoCfg.getCodePath() + "/rock-" + AutoCfg.getSystemCode() + "/rock-" + AutoCfg.getSystemCode() + "-svc/src/main/java";
			myatisContext.put("javaModelFoderPath", javaModelFoderPath);
			// mapper源代码路径：代码位置/系统文件夹名（rock-upms）/工程文件夹名（rock-upms-svc）/java文件路径（src/main/java）
			myatisContext.put("javaMapperFoderPath", javaMapperFoderPath);
			myatisContext.put("generator_jdbc_password", AESUtil.getInstance().decrypt(AutoCfg.getJdbcPassword()));
			myatisContext.put("last_insert_id_tables", return_insert_id_tables);
			myatisContext.put("jdbcDriver", AutoCfg.getJdbcDriver());
			myatisContext.put("jdbcUrl", AutoCfg.getJdbcUrl().replace("&", "&amp;"));
			myatisContext.put("jdbcUsername", AutoCfg.getJdbcUsername());
			myatisContext.put("jdbcPassword", AESUtil.getInstance().decrypt(AutoCfg.getJdbcPassword()));
			// 调用模板引擎，生产mybatis自动代码生成文件
			try {
				VelocityUtil.generate(generatorConfigVm, generatorConfig_xml, myatisContext);
				// 删除旧代码:实体类java文件
				deleteDir(new File(javaModelFoderPath));// 创建目录
				FileUtil.createDir(javaModelFoderPath);
				// 删除旧代码：mapper映射文件和mapper配置文件，放在同一目录的
				deleteDir(new File(javaMapperFoderPath));
				FileUtil.createDir(javaMapperFoderPath);// 创建目录
			} catch (Exception e) {
				e.printStackTrace();
			}
			log.trace("======>运行MybatisGenerator.xml文件 ：begin");
			List<String> warnings = new ArrayList<String>();
			File configFile = new File(generatorConfig_xml);
			ConfigurationParser cp = new ConfigurationParser(warnings);
			Configuration config = cp.parseConfiguration(configFile);
			DefaultShellCallback callback = new DefaultShellCallback(true);
			MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
			myBatisGenerator.generate(null);
			for (String warning : warnings) {
				System.out.println(warning);
			}
			log.trace("======>运行MybatisGenerator.xml文件 ：end");
		}
		log.trace("======>generatModel end");
	}

	/**
	 * 生成实体service接口类
	 */
	public void generatModelIService() {
		if (tableList != null) {
			// 接口文件夹路径:D:/RockPro/autocode/rock-upms/rock-upms-api/src/main/java/com/rock/upms/api/model/service）
			String iserviceFoderPath = AutoCfg.getCodePath() + "/rock-" + AutoCfg.getSystemCode() + "/rock-" + AutoCfg.getSystemCode() + "-api/src/main/java/com/rock/"
					+ AutoCfg.getSystemCode() + "/api/model/service";
			// 清空原有文件夹
			FileUtil.DeleteFolder(iserviceFoderPath);
			// 创建空目录
			FileUtil.createDir(iserviceFoderPath);
			iserviceVm = MybatisGeneratUtil.class.getResource(iserviceVm).getPath().replaceFirst("/", "");
			for (int i = 0; i < tableList.size(); i++) {
				// 表名大驼峰
				String modelName = StringUtil.lineToHump(ObjectUtils.toString(tableList.get(i).get("table_name")));
				String iserviceJavaFilePath = iserviceFoderPath + "/I" + modelName + "Service.java";
				FileUtil.deleteFile(iserviceJavaFilePath);// 删除原有文件
				log.trace("======>iserviceFoderPath：" + iserviceFoderPath);
				log.trace("======>iserviceJavaFilePath：" + iserviceJavaFilePath);
				// 生成实体类DAO接口类
				VelocityContext context = new VelocityContext();
				// 接口类包名package com.rock.upms.api.model.service;
				context.put("ientityServicePackageName", "com.rock." + AutoCfg.getSystemCode() + ".api.model.service");
				// 实体类名：大驼峰表名
				context.put("entityClassName", modelName);
				// 实体包名package com.rock.upms.model;
				context.put("entityPackageName", "com.rock." + AutoCfg.getSystemCode() + ".model");
				String ctime = new SimpleDateFormat("yyyy/M/d").format(new Date());
				context.put("ctime", ctime);
				try {
					VelocityUtil.generate(iserviceVm, iserviceJavaFilePath, context);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 生成实体service接口实现类
	 */
	public void generatModelServiceImpl(Map<String, String> return_insert_id_tables) {
		if (tableList != null) {
			serviceImplVm = MybatisGeneratUtil.class.getResource(serviceImplVm).getPath().replaceFirst("/", "");
			// 接口实现类文件夹路径:D:/RockPro/autocode/rock-upms/rock-upms-svc/src/main/java/com/rock/upms/svc/model/service/impl）
			String serviceImplFoderPath = AutoCfg.getCodePath() + "/rock-" + AutoCfg.getSystemCode() + "/rock-" + AutoCfg.getSystemCode() + "-svc/src/main/java/com/rock/"
					+ AutoCfg.getSystemCode() + "/svc/model/service/impl";
			FileUtil.createDir(serviceImplFoderPath);
			for (int i = 0; i < tableList.size(); i++) {
				// 表名大驼峰
				String modelName = StringUtil.lineToHump(ObjectUtils.toString(tableList.get(i).get("table_name")));
				String serviceImplJavaFilePath = serviceImplFoderPath + "/" + modelName + "Service.java";
				FileUtil.deleteFile(serviceImplJavaFilePath);// 删除原有文件
				VelocityContext context = new VelocityContext();
				// 接口实现类包名package com.rock.upms.svc.model.service.impl;
				context.put("entityServiceImplPackageName", "com.rock." + AutoCfg.getSystemCode() + ".svc.model.service.impl");
				// 接口包名
				context.put("ientityServicePackageName", "com.rock." + AutoCfg.getSystemCode() + ".api.model.service");
				// 实体类名：大驼峰表名
				context.put("entityClassName", modelName);
				context.put("entityMapperPackageName", "com.rock." + AutoCfg.getSystemCode() + ".svc.dao.model.mapper");
				context.put("entityMappeCase", StringUtil.toLowerCaseFirstOne(modelName));
				// 实体包名package com.rock.upms.model;
				context.put("entityPackageName", "com.rock." + AutoCfg.getSystemCode() + ".model");
				String ctime = new SimpleDateFormat("yyyy/M/d").format(new Date());
				String overrideInsert = "0";// 是否重写inserti方法
				if (return_insert_id_tables.containsKey(ObjectUtils.toString(tableList.get(i).get("table_name")).toLowerCase())) {
					overrideInsert = "0";
				} else {
					overrideInsert = "1";
				}
				context.put("overrideInsert", overrideInsert);
				context.put("ctime", ctime);
				try {
					VelocityUtil.generate(serviceImplVm, serviceImplJavaFilePath, context);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 模态窗口模式的CRUD jsp文件生成
	 * 
	 * @param tableName
	 *            表名
	 * @param columnList
	 *            数据列不显示的字段
	 */
	public void generatWebModal(String tableName, String pkCode, String tableComment, String subSystemCode, Set<String> hideColumnSet) {
		modalCrudJspVm = MybatisGeneratUtil.class.getResource(modalCrudJspVm).getPath().replaceFirst("/", "");
		pkCode = StringUtil.toLowerCaseFirstOne(StringUtil.lineToHump(pkCode));// 转小驼峰
		Set<String> hideSet = new HashSet<>();
		if (hideColumnSet != null) {
			// 将字段名转为小驼峰
			for (String string : hideColumnSet) {
				System.out.println("====set:" + StringUtil.toLowerCaseFirstOne(StringUtil.lineToHump(string)));
				hideSet.add(StringUtil.toLowerCaseFirstOne(StringUtil.lineToHump(string)));
			}
		}
		String sql = "";// 获取表的字段名，字段备注，key属性（PRI主键，UNI唯一），是否可以为空，数据类型，最大长度，字段顺序号
		if (AutoCfg.getDatabaseType().equals("mysql")) {
			sql = "select column_name  ,column_comment,column_key ,is_nullable ,data_type   ,character_maximum_length     from INFORMATION_SCHEMA.Columns where table_name='"
					+ tableName + "' order by ordinal_position asc ";
		}
		if (AutoCfg.getDatabaseType().equals("oracle")) {
		}
		JdbcUtil jdbcUtil = new JdbcUtil(AutoCfg.getJdbcDriver(), AutoCfg.getJdbcUrl(), AutoCfg.getJdbcUsername(), AESUtil.getInstance().decrypt(AutoCfg.getJdbcPassword()));
		List<Map> result = null;
		try {
			result = jdbcUtil.selectByParams(sql, null);// 从数据库获取表属性
		} catch (SQLException e) {
			e.printStackTrace();
		}
		jdbcUtil.release();
		// 以下为代码生成业务逻辑
		if (result != null) {
			log.trace("======>" + tableName + " column size:" + result.size());
			for (int i = 0; i < result.size(); i++) {
				// 将字段改为小驼峰
				HashMap<String, String> map = (HashMap) result.get(i);
				String newColName = StringUtil.toLowerCaseFirstOne(StringUtil.lineToHump(map.get("COLUMN_NAME")));
				result.get(i).put("COLUMN_NAME", newColName);// 覆盖掉原来的值
				System.out.println("=====newColName:" + newColName);
			}
			// D:/RockPro/git/rock/rock-upms/rock-upms-web/src/main/webapp/WEB-INF/views/upms/person
			String jspFoder = AutoCfg.getCodePath() + "/rock-" + AutoCfg.getSystemCode() + "/rock-" + AutoCfg.getSystemCode() + "-web/src/main/webapp/WEB-INF/views/"
					+ AutoCfg.getSystemCode() + "/" + subSystemCode;
			String jspFile = jspFoder + "/" + StringUtil.toLowerCaseFirstOne(StringUtil.lineToHump(tableName) + ".jsp");
			// D:/RockPro/git/rock/rock-upms/rock-upms-web/src/main/java/com/rock/upms/web/dept/controller
			String controllerJavaFoder = AutoCfg.getCodePath() + "/rock-" + AutoCfg.getSystemCode() + "/rock-" + AutoCfg.getSystemCode() + "-web/src/main/java/com/rock/"
					+ AutoCfg.getSystemCode() + "/web/" + subSystemCode + "/controller";
			String controllerJavaFile = controllerJavaFoder + "/" + StringUtil.lineToHump(tableName) + "Controller.java";
			VelocityContext jspContext = new VelocityContext();
			jspContext.put("hideColumnSet", hideSet);
			jspContext.put("ColumnList", result);// 表字段属性
			jspContext.put("tableName", tableName);// 表名
			jspContext.put("caseName", StringUtil.toLowerCaseFirstOne(StringUtil.lineToHump(tableName)));// 实例名
			jspContext.put("pkCode", pkCode);// 主键
			jspContext.put("tableComment", tableComment);// 表备注
			jspContext.put("systemCode", AutoCfg.getSystemCode());// 系统名
			jspContext.put("subSystemCode", subSystemCode);// 子系统名
			VelocityContext controllerContext = new VelocityContext();
			controllerContext.put("pkCode", pkCode);// 主键
			controllerContext.put("className", StringUtil.lineToHump(tableName));
			controllerContext.put("systemCode", AutoCfg.getSystemCode());
			controllerContext.put("subSystemCode", subSystemCode);
			controllerContext.put("caseName", StringUtil.toLowerCaseFirstOne(StringUtil.lineToHump(tableName)));// 实例名
			try {
				// 生成jsp文件
				FileUtil.createDir(jspFoder);// 创建文件夹
				FileUtil.deleteFile(jspFile);// 刪除文件重新生成
				VelocityUtil.generate(modalCrudJspVm, jspFile, jspContext);// jsp文件
				// 生成controller java文件
				FileUtil.createDir(controllerJavaFoder);// 创建文件夹
				FileUtil.deleteFile(controllerJavaFile);// 刪除文件重新生成
				VelocityUtil.generate(modalControllerVm, controllerJavaFile, controllerContext);// jsp文件
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	// 递归删除非空文件夹
	public static void deleteDir(File dir) {
		if (dir.isDirectory()) {
			File[] files = dir.listFiles();
			for (int i = 0; i < files.length; i++) {
				deleteDir(files[i]);
			}
		}
		dir.delete();
	}
}
